﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Pathfinding;
using QFramework;
using UnityEngine;

namespace Gp.Scripts.Core {
    /// <summary>
    /// 行动计数容器。提供行动计数查询、逻辑处理接口。<br/>
    /// 保证在后续更改结构时，只需删除这个类就能移除行动计数功能。
    /// </summary>
    public class AITurnCounter {
        /// <summary>
        /// 存储单位行动计数的字典。key: BaseUnit的InstanceId, value: 倒计时 
        /// </summary>
        private readonly Dictionary<int, int> _dic = new();

        private AIPlayer _player;
        private const int TestDefaultValue = 2;
        private const int TestAtkRange = 3;
        private const string TestIndicatorName = "Ability Indicator";


        private HashSet<int> _attackPrepareUnits = new();

        /// <summary>
        /// 用于防止单位同时移动
        /// </summary>
        private int _moveWaitCnt = 0;

        public void OnInit(AIPlayer player) {
            _player = player;
            Global.Get<BattleSystem>().RegisterEvent<Event_Unit.Death>(args => {
                var indicator = args.Unit.transform.Find(TestIndicatorName);
                if (indicator != null) indicator.Hide();
            });
        }

        public IEnumerator ReduceTurnCounter() {
            // yield break;
            // 阻塞行动
            Global.Get<BattleSystem>().BlockInput(this);
            var model = Global.Get<BattleSystem>().BattleSettle;
            CoroutineTask task = CoroutineTask.Sequence();
            
            
            foreach (var u in model.GetUnitsByPlayer(_player.PlayerNumber)) {
                if (u == null) continue;
                var key = u.GetInstanceID();
                if (!_dic.ContainsKey(key)) {
                    // 初始化计数
                    _dic[key] = TestDefaultValue;
                }
                
                _dic[key] -= 1;
                // 计数为零，则单位进入行动状态。
                if (_dic[key] <= 0) {
                    // 让单位进行下一步行动的决策
                    var func = AiBehaviour(u);
                    if (func != null) task.Add(func);
                }
                
                _dic[key] = Math.Max(_dic[key], 1);
                
                // u.TriggerEvent(new TurnCountChange(_dic[key]), false);
                BaseUnit targetUnit = model.GetUnitsByPlayer(PlayerConst.PlayerUnitNumber).FirstOrDefault();
                
                
                yield return MoveExecuteProcess(u, targetUnit);
            }
            
            
            _moveWaitCnt = 0;
            Global.Get<BattleSystem>().UnBlockInput(this);
        }


        private Func<IEnumerator> AiBehaviour(BaseUnit aiUnit) {
            // 如果单位正处于准备攻击状态
            int key = aiUnit.GetInstanceID();

            var model = Global.Get<BattleSystem>().BattleSettle;
            BaseUnit targetUnit = model.GetUnitsByPlayer(PlayerConst.PlayerUnitNumber).FirstOrDefault();
            if (targetUnit == null) return null;


            // 判断目标与自身距离
            Vector3 targetPos = targetUnit.transform.position;
            Vector3 selfPos = aiUnit.transform.position;
            float distance = Vector3.Distance(selfPos, targetPos);
            // 如果距离小于等于攻击距离（测试用），则触发攻击行为。
            if (distance <= TestAtkRange || _attackPrepareUnits.Contains(key)) {
                return () => AtkProcess(aiUnit, targetUnit);
            }
            // 否则触发移动行为
            else {
                return () => MoveExecuteProcess(aiUnit, targetUnit);
            }
        }


        private IEnumerator AtkProcess(BaseUnit unit, BaseUnit targetUnit) {
            if (unit == null) yield break;

            int key = unit.GetInstanceID();
            // 转向玩家单位
            unit.Model.ForwardToTarget(targetUnit.transform.position);
            if (!_attackPrepareUnits.Contains(key)) {
                // 延时2回合执行
                _attackPrepareUnits.Add(key);
                _dic[targetUnit.GetInstanceID()] = TestDefaultValue;
                // unit.TriggerEvent(new TurnCountChange(TestDefaultValue), false);
                // 显示攻击指示
                TempSetAtkIndicator(unit, true);
            }
            else {
                // 关闭指示器
                TempSetAtkIndicator(unit, false);
                // 执行攻击逻辑
                _attackPrepareUnits.Remove(key);
                if (Vector3.Distance(unit.transform.position, targetUnit.transform.position) <= TestAtkRange)
                    yield return unit.ComSkill.WeaponAttack.ExecuteWeaponAttack(new AttackContext(targetUnit));
            }
        }


        private void TempSetAtkIndicator(BaseUnit unit, bool isActive) {
            var indicator = unit.transform.Find(TestIndicatorName);
            if (indicator == null) return;
            indicator.gameObject.SetActive(isActive);
        }


        private IEnumerator MoveExecuteProcess(BaseUnit aiUnit, BaseUnit targetUnit) {
            // 距离小于1则不移动
            // 随机等待一段时间
            Vector3 targetPos = targetUnit.transform.position;
            if (Vector3.Distance(aiUnit.transform.position, targetPos) < 1.5f) yield break;
            if (!CalFormationPosition(aiUnit.transform.position, targetPos, out Vector3 resPos)) yield break;

            // 将目标位置设置为在攻击范围内的阵型位置
            // yield return aiUnit.ComSkill.MoveSkill.WalkTo(resPos, 8);
        }


        /// <summary>
        /// AI编队的移动位置修正，使AI能够正确包围目标。修正点为目标周围一圈离自身最近的位置
        /// </summary>
        /// <returns></returns>
        private bool CalFormationPosition(Vector3 sourcePos, Vector3 targetPos, out Vector3 resPos) {
            // resPos = default;
            // // 获得目标周围所有可达点
            // HashSet<GraphNode> set = GetAroundNodes(targetPos);
            // if (set.Count == 0) return false;
            //
            // Vector3 minPoint = default;
            // float minDistance = float.MaxValue;
            //
            // // 取所有可达点中最短
            // foreach (var node in set) {
            //     var nodeDestination = (Vector3) node.position;
            //
            //     var path = Global.Get<BattleSystem>().BattleSettle.BattleCellGrid.ConstructPath();
            //     // AstarPath.StartPath(path);
            //     path.BlockUntilCalculated();
            //     if (path.error) continue;
            //     // 使用距离目标点的距离作为修正值，保证尽可能接近目标点
            //     float fixValue = Vector3.Distance(nodeDestination, targetPos);
            //     var pathLen = path.GetTotalLength() * fixValue;
            //     if (pathLen > minDistance) continue;
            //     minDistance = pathLen;
            //     minPoint = nodeDestination;
            // }
            //
            // resPos = minPoint;
            // return minDistance < float.MaxValue;
            resPos = Vector3.zero;
            return false;
        }

        private HashSet<GraphNode> GetAroundNodes(Vector3 targetPos) {
            Helpers.NavHelper.SamplePosition(targetPos, NNConstraint.None, out NNInfo node);
            HashSet<GraphNode> set = new();

            if (node.node is not GridNodeBase sourceNode) return set;
            Queue<GridNodeBase> queue = new();
            queue.Enqueue(sourceNode);

            int cnt = 2;
            while (queue.Count != 0 && cnt-- > 0) {
                int temp = queue.Count;
                for (int t = 0; t < temp; t++)
                {
                    var n = queue.Dequeue();
                    foreach (var other in n.GetNeighbours())
                    {
                        if (other.Walkable) set.Add(other);
                        else queue.Enqueue(other);
                    }
                }
            }

            return set;
        }
    }
}